#include <event/eventhandler.h>

#include <queue>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace events
{

    CRITICAL_SECTION event_critical_section;

    std::queue<Event *> appqueue;
    std::queue<Event *> mainqueue;

    void remEvent(Event * event)
    {
        if(event->_copies <= 1)
            delete event;
        else
            (event->_copies)--;
    }

    class MemManager
    {
    public:
        MemManager()
        {
            InitializeCriticalSection(&event_critical_section);
        }
        ~MemManager()
        {
            DeleteCriticalSection(&event_critical_section);

            while(!appqueue.empty())
            {
                remEvent(appqueue.front());
                appqueue.pop();
            }

            while(!mainqueue.empty())
            {
                remEvent(mainqueue.front());
                mainqueue.pop();
            }
        }
    };

    MemManager manager;

    Event::Event()
    {
        _queue = EVERY_QUEUE;
        _type = UNKNOWN_EVENT;
    }

    Event::~Event()
    {
    }

    Event::Event(const Event & rhs)
    {
        _queue = rhs._queue;
        _type = rhs._type;
    }

    Event::Event(const char * type, unsigned long queue)
    {
        _type = type;
        _queue = queue;
    }

    const char * Event::type() const
    {
        return _type;
    }

    Event * Event::copy() const {
      return new Event(*this);
    }

    void Event::_copyData(Event * copy) const {
      copy->_type = _type;
      copy->_queue = _queue;
    }

    void Fire(Event * event)
    {
        EnterCriticalSection(&event_critical_section);

        event->_copies = 0;

        if(event->_queue & APP_QUEUE)
        {
            appqueue.push(event);
            (event->_copies)++;
        }

        if(event->_queue & MAIN_QUEUE)
        {
            mainqueue.push(event);
            (event->_copies)++;
        }

        LeaveCriticalSection(&event_critical_section);
    }

    const Event * PeekEvent(unsigned long queue)
    {
        EnterCriticalSection(&event_critical_section);

        Event * retval = NULL;

        switch(queue)
        {
        case APP_QUEUE:
            if(!appqueue.empty())
                retval = appqueue.front();
            break;

        case MAIN_QUEUE:
            if(!mainqueue.empty())
                retval = mainqueue.front();
            break;
        }
        
        LeaveCriticalSection(&event_critical_section);
        return retval;
    }

    void PopEvent(unsigned long queue)
    {
        EnterCriticalSection(&event_critical_section);

        if((queue & APP_QUEUE) && !appqueue.empty())
        {
            remEvent(appqueue.front());
            appqueue.pop();
        }

        if((queue & MAIN_QUEUE) && !mainqueue.empty())
        {
            remEvent(mainqueue.front());
            mainqueue.pop();
        }

        LeaveCriticalSection(&event_critical_section);
    }

}; // end namespace events
